/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. The ASF
 * licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package top.shaozuo.simple.rest.client;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import javax.ws.rs.HttpMethod;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import top.shaozuo.simple.rest.core.DefaultResponse;

/**
 * HTTP POST Method {@link Invocation}
 *
 * @author shaouzo
 */
class HttpPostInvocation implements Invocation {
	private ObjectMapper mapper = new ObjectMapper();

	private final URI uri;

	private final URL url;

	private final MultivaluedMap<String, Object> headers;

	private final Entity<?> entity;

	HttpPostInvocation(URI uri, MultivaluedMap<String, Object> headers, Entity<?> entity) {
		this.uri = uri;
		this.headers = headers;
		this.entity = entity;
		try {
			this.url = uri.toURL();
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException();
		}
	}

	@Override
	public Invocation property(String name, Object value) {
		return this;
	}

	@Override
	public Response invoke() {
		HttpURLConnection connection = null;
		try {
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod(HttpMethod.POST);
			setRequestHeaders(connection);
			setRequestEntity(connection);
			int statusCode = connection.getResponseCode();
			DefaultResponse response = new DefaultResponse();
			response.setConnection(connection);
			response.setStatus(statusCode);
			return response;

		} catch (IOException e) {
			// TODO Error handler
		}
		return null;
	}

	private void setRequestEntity(HttpURLConnection connection) {
		if (entity != null) {
			connection.setDoOutput(true);
			// 设置文件字符集:
			connection.setRequestProperty("Charset", entity.getEncoding());
			// 转换为字节数组
			String jsonStr = null;
			if (entity.getEntity() != null) {
				try {
					jsonStr = mapper.writeValueAsString(entity.getEntity());
				} catch (JsonProcessingException e) {
					e.printStackTrace();
				}
			}
			// 设置文件长度
			System.out.println(jsonStr);
			byte[] data = jsonStr == null ? new byte[0] : jsonStr.getBytes();
			connection.setRequestProperty("Content-Length", String.valueOf(data.length));
			// 设置文件类型: 
			// connection.setRequestProperty("Content-Type", entity.getMediaType().toString());
			// 默认调用 RuntimeDelegate.getInstance().createHeaderDelegate(MediaType.class).toString(this);
			//但是没有实现，所以就直接写死
			connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
			try (OutputStream outwritestream = connection.getOutputStream();) {
				outwritestream.write(data);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private void setRequestHeaders(HttpURLConnection connection) {
		for (Map.Entry<String, List<Object>> entry : headers.entrySet()) {
			String headerName = entry.getKey();
			for (Object headerValue : entry.getValue()) {
				connection.setRequestProperty(headerName, headerValue.toString());
			}
		}
	}

	@Override
	public <T> T invoke(Class<T> responseType) {
		Response response = invoke();
		return response.readEntity(responseType);
	}

	@Override
	public <T> T invoke(GenericType<T> responseType) {
		Response response = invoke();
		return response.readEntity(responseType);
	}

	@Override
	public Future<Response> submit() {
		return null;
	}

	@Override
	public <T> Future<T> submit(Class<T> responseType) {
		return null;
	}

	@Override
	public <T> Future<T> submit(GenericType<T> responseType) {
		return null;
	}

	@Override
	public <T> Future<T> submit(InvocationCallback<T> callback) {
		return null;
	}
}
